#include "stdafx.h"
#include "BufferManager.h"

using namespace Rendering;

/// <summary>Gets the size of a specified buffer.</summary>
/// <param name="buffer">[in] Direct3D buffer.</param>
/// <returns>The size of the buffer.</returns>
int BufferManager::GetBufferSize(ID3D11Buffer* buffer)
{
	if (buffer == nullptr)
		return 0;

	D3D11_BUFFER_DESC bufferDesc;
	buffer->GetDesc(&bufferDesc);
	return bufferDesc.ByteWidth;
}

/// <summary>Creates an empty vertex buffer which should be filled afterwards.</summary>
/// <param name="device">[in] Direct3D device for the buffer.</param>
/// <param name="byteWidth">[in] Size in bytes of the buffer.</param>
/// <param name="vertexBuffer">[out] The pointer for the buffer.</param>
void BufferManager::CreateVertexBuffer(ID3D11Device* device, size_t byteWidth,  ID3D11Buffer **vertexBuffer)
{
	*vertexBuffer = nullptr;

	byteWidth = ((byteWidth + 15)/16)*16; // make it multiple of 16

	D3D11_BUFFER_DESC vertexDesc;

	ZeroMemory(&vertexDesc, sizeof( vertexDesc ) );
	vertexDesc.Usage = D3D11_USAGE_DYNAMIC;
	vertexDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	vertexDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	vertexDesc.ByteWidth = static_cast<UINT>(byteWidth);
	vertexDesc.MiscFlags = 0;
	vertexDesc.StructureByteStride = 0;

	ID3D11BufferPtr vertexBufferInternal;
	IF_FAILED_THROW_HR(device->CreateBuffer(&vertexDesc, nullptr, &vertexBufferInternal));

	*vertexBuffer = vertexBufferInternal.Detach();
}

/// <summary>Creates an empty index buffer which should be filled afterwards.</summary>
/// <param name="device">[in] Direct3D device for the buffer.</param>
/// <param name="byteWidth">[in] Size in bytes of the buffer.</param>
/// <param name="indexBuffer">[out] The pointer for the buffer.</param>
void BufferManager::CreateIndexBuffer(ID3D11Device* device, size_t byteWidth, ID3D11Buffer** indexBuffer)
{
	*indexBuffer = nullptr;
	ID3D11BufferPtr indexBufferInternal;

	byteWidth = ((byteWidth + 15)/16)*16; // make it multiple of 16

	D3D11_BUFFER_DESC indexBufferDesc;
	ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc));
	// Set up the description of the dynamic index buffer.
	indexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; //indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
	indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	indexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; //indexBufferDesc.CPUAccessFlags = 0;
	indexBufferDesc.MiscFlags = 0;
	indexBufferDesc.StructureByteStride = 0;
	indexBufferDesc.ByteWidth = static_cast<UINT>(byteWidth);
	
	// Create the index buffer.
	IF_FAILED_THROW_HR(device->CreateBuffer(&indexBufferDesc, nullptr, &indexBufferInternal));
	*indexBuffer = indexBufferInternal.Detach();
}

/// <summary>Creates an index buffer.</summary>
/// <param name="device">[in] Direct3D device for the buffer.</param>
/// <param name="numIndices">[in] Number of elements in the buffer.</param>
/// <param name="indexData">[in] The index elements.</param>
/// <param name="indexBuffer">[out] The pointer for the buffer.</param>
void BufferManager::CreateIndexBuffer(ID3D11Device* device, unsigned int numIndices, unsigned short *indexData, ID3D11Buffer **indexBuffer)
{
    *indexBuffer = nullptr;

    D3D11_BUFFER_DESC IndexBufferDesc;
    IndexBufferDesc.ByteWidth = sizeof(unsigned short) * numIndices;
    IndexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    IndexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    IndexBufferDesc.CPUAccessFlags = 0;
    IndexBufferDesc.MiscFlags = 0;
    IndexBufferDesc.StructureByteStride = 0;

    D3D11_SUBRESOURCE_DATA indexBufferData;
    indexBufferData.pSysMem = indexData;
    indexBufferData.SysMemPitch = 0;
    indexBufferData.SysMemSlicePitch = 0;

    ID3D11BufferPtr indexBufferInternal;
    IF_FAILED_THROW_HR(device->CreateBuffer(&IndexBufferDesc, &indexBufferData, &indexBufferInternal));

    *indexBuffer = indexBufferInternal.Detach();
}

/// <summary>Creates an empty constant buffer which should be filled afterwards.</summary>
/// <param name="device">[in] Direct3D device for the buffer.</param>
/// <param name="byteWidth">[in] Size in bytes of the buffer.</param>
/// <param name="outBuffer">[out] The pointer for the buffer.</param>
void BufferManager::CreateConstantBuffer(ID3D11Device* device, int byteWidth, ID3D11Buffer** outBuffer)
{
	*outBuffer = nullptr;

	D3D11_BUFFER_DESC constBufferDesc;
	ZeroMemory( &constBufferDesc, sizeof( constBufferDesc) );

    constBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    constBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    constBufferDesc.CPUAccessFlags = 0;
    constBufferDesc.ByteWidth = ((byteWidth + 15)/16)*16;

	ID3D11BufferPtr buffer;
	IF_FAILED_THROW_HR(device->CreateBuffer(&constBufferDesc, nullptr, &buffer));

	*outBuffer = buffer.Detach();
}